home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / bin / apport-collect < prev    next >
Text File  |  2009-11-03  |  6KB  |  183 lines

  1. #!/usr/bin/python
  2.  
  3. # Download a Launchpad bug report, get its source package, check if it has
  4. # apport hooks, and if so, run and upload them.
  5. #
  6. # Copyright (c) 2009 Canonical Ltd.
  7. # Author: Martin Pitt <martin.pitt@ubuntu.com>
  8. #
  9. # This program is free software; you can redistribute it and/or modify it
  10. # under the terms of the GNU General Public License as published by the
  11. # Free Software Foundation; either version 2 of the License, or (at your
  12. # option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
  13. # the full text of the license.
  14.  
  15. import sys, os.path, optparse, tempfile, re, email
  16. from glob import glob
  17.  
  18. import apport
  19. from launchpadlib.errors import HTTPError
  20. from apport.crashdb_impl.launchpad import CrashDatabase
  21.  
  22. bug_target_re = re.compile(
  23.     r'/ubuntu/(?:(?P<suite>[^/]+)/)?\+source/(?P<source>[^/]+)$')
  24.  
  25. def upload(report, bug):
  26.     '''Upload collected information to Launchpad bug.'''
  27.  
  28.     print 'Uploading additional information to Launchpad bug...'
  29.  
  30.     # we want to reuse the knowledge of write_mime() with all its different input
  31.     # types and output formatting; however, we have to dissect the mime ourselves,
  32.     # since we can't just upload it as a blob
  33.     mime = tempfile.TemporaryFile()
  34.     report.write_mime(mime)
  35.     mime.flush()
  36.     mime.seek(0)
  37.     msg = email.message_from_file(mime)
  38.     msg_iter = msg.walk()
  39.  
  40.     # first part is the multipart container
  41.     part = msg_iter.next()
  42.     assert part.is_multipart()
  43.  
  44.     # second part should be an inline text/plain attachments with all short
  45.     # fields
  46.     part = msg_iter.next()
  47.     assert not part.is_multipart()
  48.     assert part.get_content_type() == 'text/plain'
  49.     
  50.     print'   short text data...'
  51.     bug.newMessage(content=part.get_payload(decode=True), 
  52.         subject='apport-collect data')
  53.  
  54.     # other parts are the attachments:
  55.     for part in msg_iter:
  56.         print '   attachment: %s...' % part.get_filename()
  57.         bug.addAttachment(comment='', 
  58.             description=part.get_filename(),
  59.             content_type=None,
  60.             data=part.get_payload(decode=True),
  61.             filename=part.get_filename(), is_patch=False)
  62.  
  63.     # change bug status from "Incomplete"
  64.     for task in bug.bug_tasks:
  65.         if task.status == 'Incomplete':
  66.             task.transitionToStatus(status='New')
  67.  
  68. def collect(report, package):
  69.     '''Collect information for given package.'''
  70.  
  71.     print 'Collecting apport information for source package %s...' % package
  72.     try:
  73.         report.add_package_info(package)
  74.     except ValueError:
  75.         # this happens for source package tasks which do not have an identical
  76.         # binary package name
  77.         pass
  78.     report.add_hooks_info(None)
  79.  
  80. #
  81. # main
  82. #
  83.  
  84. optparser = optparse.OptionParser('%prog [options] <Launchpad bug number>')
  85. optparser.add_option('-p', '--package', 
  86.     help="Collect information for this package. If not given, it will be inferred from the bug report's source package tasks.",
  87.     type='string', dest='package')
  88. (opts, args) = optparser.parse_args()
  89.  
  90. if len(args) != 1:
  91.     optparser.error('incorrect number of arguments; use --help for a short online help')
  92.     sys.exit(1)
  93.  
  94. try:
  95.     bug_number = int(args[0])
  96. except ValueError:
  97.     optparser.error('invalid bug report number')
  98.     sys.exit(1)
  99.  
  100. print 'Logging into Launchpad... You have to allow "Change anything" privileges.'
  101. crashdb = CrashDatabase(None, None, {'distro': 'ubuntu'})
  102.  
  103. print 'Downloading bug information...'
  104.  
  105. try:
  106.     bug = crashdb.launchpad.bugs[int(bug_number)]
  107. except KeyError:
  108.     print 'The bug number %s does not exist in Launchpad.' % bug_number
  109.     sys.exit(1)
  110.  
  111. if bug.owner.name != crashdb.launchpad.me.name:
  112.     print 'You are not the reporter of bug %s.' % bug_number
  113.     while True:
  114.         val = raw_input('Is that really the bug you want to update? [y/N]')
  115.         if val.lower() in ('y', 'yes'):
  116.             break
  117.         elif val.lower() in ('n', 'no', ''):
  118.             sys.exit(1)
  119.         else:
  120.             print 'Invalid answer.'
  121.  
  122. report = apport.Report('Bug')
  123.  
  124. print 'Bug title:', bug.title
  125. info_collected = False
  126. if opts.package:
  127.     collect(report, opts.package)
  128.     info_collected = True
  129. else:
  130.     # determine bug tasks and collect for those
  131.     for task in bug.bug_tasks:
  132.         match = bug_target_re.search(task.target.self_link)
  133.         if not match:
  134.             print 'Ignoring task', task.target
  135.             continue
  136.         if task.status in ('Invalid', "Won't Fix", 'Fix Released'):
  137.             print 'Ignoring task %s because it is closed' % task.target
  138.             continue
  139.         src = match.group('source')
  140.         report['SourcePackage'] = src
  141.         report['Package'] = src # no way to find this out
  142.         # we either must have the package installed or a source package hook
  143.         # available to collect sensible information
  144.         try:
  145.             apport.packaging.get_version(report['Package'])
  146.             info_collected = True
  147.         except ValueError:
  148.             if os.path.exists('/usr/share/apport/package-hooks/source_%s.py' %
  149.                     report['SourcePackage']):
  150.                 info_collected = True
  151.             else:
  152.                 print 'Package %s not installed and no hook available, ignoring' % src
  153.                 continue
  154.         collect(report, src)
  155.  
  156. report.add_os_info()
  157. report.add_user_info()
  158. report.add_proc_environ()
  159.  
  160. if not info_collected:
  161.     print 'No additional information collected.'
  162.     sys.exit(0)
  163.  
  164. # delete the uninteresting keys
  165. del report['ProblemType']
  166. del report['Date']
  167. try:
  168.     del report['SourcePackage']
  169. except KeyError:
  170.     pass
  171.  
  172. try:
  173.     upload(report, bug)
  174.  
  175.     bug = crashdb.launchpad.bugs[int(bug_number)] # LP#336866 workaround
  176.     x = bug.tags[:] # LP#254901 workaround
  177.     x.append('apport-collected')
  178.     bug.tags = x
  179.     bug.lp_save()
  180. except HTTPError, e:
  181.     print >> sys.stderr, 'Error connecting to Launchpad: %s\nYou have to allow "Change anything" privileges.\nYou can reset the credentials by removing the file "~/.cache/apport/launchpad.credentials."' % str(e)
  182.     sys.exit(1)
  183.